package com.panopset;

import java.io.File;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import com.panopset.MavenAuditor.MavenDependency;
import com.panopset.compat.RezIO;
import com.panopset.compat.Strings;

/**
 *
 * Maven pom to signed repository.
 *
 * @author Karl Dinwiddie
 *
 */
public final class Pom2repo {

    /**
     * Create a maven repository from a pom.xml file, in which all the jars are
     * signed. This is useful for publishing Web Start (JNLP) applications from
     * maven projects.
     *
     * @param keyStore
     *            Key store, something like "temp/store".
     * @param pom
     *            This is your project pom.xml file.
     * @param jnlpRepos
     *            This is where you want to put your new repository.
     * @param dname
     *            This is your dname, can't have spaces, sorry. Something like
     *            cn=Dinwiddie,ou=Panopset,o=Panopset,c=US.
     * @param password
     *            This is your password, Widgets.promptForPassword() might be
     *            used for this. Widgets is in Panopset swingframe.
     * @param mainJarName Main jar name.
     * @return Set<MavenAuditor.MavenDependency> Returns a set of the
     * dependencies, in case you want to use them to generate jnlp files or
     * something.
     * @throws Exception
     *             Exception.
     */
    public Info
            createSignedMvnRepository(final File keyStore, final File pom,
            final File jnlpRepos, final String dname, final String password,
            final String mainJarName)
            throws Exception {
        KeyManager keyManager = new KeyManager(keyStore, dname, password);
        Info rtn = new Info();
        rtn.mavenDependencies =
            new MavenAuditor().loadPomDependencies(pom);
        List<MavenDependency> removes = new ArrayList<MavenDependency>();
        for (MavenDependency dep
            : rtn.mavenDependencies) {
            if (dep.isRequired() && !dep.isOptional()) {
                System.out.println(dep.toString());
                File repoJarFile = new File(RezIO.getCanonicalPath(jnlpRepos)
                        + Strings.FILE_SEP + dep.getRelativeRepositoryJar());
                File repoPomFile = new File(RezIO.getCanonicalPath(jnlpRepos)
                        + Strings.FILE_SEP + dep.getRelativeRepositoryPom());
                File lrj = new File(dep.getLocalRepositoryJar());
                if (!lrj.exists()) {
                    removes.add(dep);
                    Util.dspmsg("Ignoring " + RezIO.getCanonicalPath(lrj)
                        + " because the jar does not exist.");
                    continue;
                }
                File lrp = new File(dep.getLocalRepositoryPom());
                if (!lrp.exists()) {
                    removes.add(dep);
                    Util.dspmsg("Ignoring " + RezIO.getCanonicalPath(lrp)
                        + " because the pom does not exist.");
                    continue;
                }
                UtilIO.copyFile(lrj, repoJarFile);
                UtilIO.copyFile(lrp, repoPomFile);
                keyManager.sign(repoJarFile);
            } else {
                removes.add(dep);
                Util.dspmsg("Ignoring " + dep.getLocalRepositoryJar()
                    + " because it is not required.");
            }
        }
        for (MavenDependency dep : removes) {
            rtn.mavenDependencies.remove(dep);
        }
        for (MavenDependency dep : rtn.mavenDependencies) {
            if (dep.isRequired()) {
                if (mainJarName.equals(dep.getArtifactId())) {
                    rtn.mainJarName = dep.getRelativeRepositoryJar();
                } else {
                    rtn.dependencies.add(dep.getRelativeRepositoryJar());
                }
            }
        }
        StringWriter depJars = new StringWriter();
        for (String depJar : rtn.dependencies) {
            depJars.append("    <jar href=\"");
            depJars.append(depJar);
            depJars.append("\"/>");
            depJars.append(Strings.getEol());
        }
        rtn.jnlpDepJarList = depJars.toString();
        return rtn;
    }

    /**
     * Dependency information.
     */
    public static final class Info {
        /**
         * Maven dependency set.
         */
        private Set<MavenAuditor.MavenDependency> mavenDependencies;

        /**
         * @return Set of maven dependencies.
         */
        public Set<MavenAuditor.MavenDependency> getMavenDependencies() {
            return mavenDependencies;
        }

        /**
         * Main jar name.
         */
        private String mainJarName = "";

        /**
         * @return Main jar name.
         */
        public String getMainJarName() {
            return mainJarName;
        }

        /**
         * Dependencies.
         */
        private List<String> dependencies = new ArrayList<String>();

        /**
         * @return Dependencies List.
         */
        public List<String> getDependencies() {
            return dependencies;
        }

        /**
         * Dependency jar list.
         */
        private String jnlpDepJarList;

        /**
         * @return JNLP dependency jar list.
         */
        public String getJnlpDepJarList() {
            return jnlpDepJarList;
        }

        /**
         * Prevent instantiation.
         */
        private Info() {
        }
    }

    /**
     * Key manager.
     */
    private static class KeyManager {
        /**
         * Password.
         */
        private final String pwd;
        /**
         * Keystore.
         */
        private final File keyStore;
        /**
         * Alias is tempkeys, who cares.
         */
        private static final String ALIAS = "tempkeys";

        /**
         * Constructor.
         *
         * @param keyStoreFile
         *            Key store file.
         * @param dname
         *            dname.
         * @param password
         *            password.
         * @throws Exception
         *             Exception.
         */
        public KeyManager(final File keyStoreFile, final String dname,
                final String password) throws Exception {
            pwd = password;
            keyStore = keyStoreFile;
            final File ks = new File(RezIO.getCanonicalPath(keyStore));
            ks.getParentFile().mkdirs();
            String cmd = "keytool -genkeypair " + "-keystore "
                    + RezIO.getCanonicalPath(keyStore) + " -validity 999999 "
                    + " -storepass " + pwd + " -keypass " + pwd + " -dname "
                    + dname + " -alias " + ALIAS;
            new Commander().exec(cmd);
        }

        /**
         * @param repoJarFile
         *            Jar to sign.
         * @throws Exception
         *             Exception.
         */
        public void sign(final File repoJarFile) throws Exception {
            String cmd = "jarsigner " + "-keystore "
                    + RezIO.getCanonicalPath(keyStore) + " -storepass " + pwd
                    + " -keypass " + pwd + " "
                    + RezIO.getCanonicalPath(repoJarFile) + " " + ALIAS;
            new Commander().exec(cmd);
        }

    }
}
